using System;
using System.ComponentModel;
using System.Linq;
using SalesPoint.Model;
using SalesPoint.Security;
using Xtensive.Orm;
using Xtensive.Orm.Configuration;
using Xtensive.Orm.Security;

namespace SalesPoint.Services
{
  public class InitializationService
  {
    private BackgroundWorker builder;

    public event EventHandler<InitializationProgressChangedEventArgs> ProgressChanged;

    public event EventHandler<InitializationCompletedEventArgs> Completed;

    public void Run(string domainName = "default")
    {
      builder = new BackgroundWorker();
      builder.WorkerReportsProgress = true;
      builder.DoWork += BuilderDoWork;
      builder.RunWorkerCompleted += BuilderRunWorkerCompleted;
      builder.ProgressChanged += BuilderProgressChanged;
      builder.RunWorkerAsync();
    }

    private void InvokeProgressChanged(InitializationProgressChangedEventArgs e)
    {
      var handler = ProgressChanged;
      if (handler != null)
        handler(this, e);
    }

    private void InvokeCompleted(InitializationCompletedEventArgs e)
    {
      var handler = Completed;
      if (handler != null)
        handler(this, e);
    }

    private void BuilderProgressChanged(object sender, ProgressChangedEventArgs e)
    {
      InvokeProgressChanged(new InitializationProgressChangedEventArgs(e.UserState as string));
    }

    private void BuilderRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      if (e.Error != null) {
        InvokeCompleted(new InitializationCompletedEventArgs(e.Error));
        return;
      }
      InvokeCompleted(new InitializationCompletedEventArgs(e.Result as Domain));
    }

    private static void BuilderDoWork(object sender, DoWorkEventArgs e)
    {
      var worker = sender as BackgroundWorker;
      worker.ReportProgress(0, "Reading configuration...");
      var dc = DomainConfiguration.Load("default");
      worker.ReportProgress(0, "Building Domain...");
      var domain = Domain.Build(dc);
      worker.ReportProgress(0, "Configuring roles and permissions...");
      var sc = new SessionConfiguration(SessionOptions.ServerProfile);

      using (var session = domain.OpenSession(sc))
      using (var ts = session.OpenTransaction()) {

        // Roles
        var roles = session.Query.All<IRole>().ToDictionary(r => r.Name, StringComparer.OrdinalIgnoreCase);
        if (roles.Count == 0) {
          new SalesRepresentativeRole(session);
          new SalesManagerRole(session);
          new SalesPresidentRole(session);
          new StockManagerRole(session);
          session.SaveChanges();
          roles = session.Query.All<IRole>().ToDictionary(r => r.Name, StringComparer.OrdinalIgnoreCase);
        }

        var employees = session.Query.All<Employee>()
          .Prefetch(em => em.Roles)
          .ToList();
        foreach (var employee in employees) {
          switch (employee.Title) {
            case "Sales Representative":
              employee.Roles.Add(roles["SalesRepresentativeRole"]);
              break;
            case "Stock Manager":
              employee.Roles.Add(roles["StockManagerRole"]);
              break;
            case "Sales Manager":
              employee.Roles.Add(roles["SalesManagerRole"]);
              break;
            case "Vice President, Sales":
              employee.Roles.Add(roles["SalesPresidentRole"]);
              break;
          }
        }
        ts.Complete();
      }
      e.Result = domain;
    }
  }
}